抱歉,您的浏览器无法访问本站
本页面需要浏览器支持(启用)JavaScript
了解详情 >

本篇主要介绍一下项目中如何发布Rest接口。其使用方式和ODATA类似,REST就是选择通过使用http协议和uri,利用client/server model对资源进行CRUD(Create/Read/Update/Delete)增删改查操作。

SAP HTTP Rest接口

一、Rest接口概念

1.介绍

REST是以Web为平台的。Web是分布式信息系统为超文本文件和其他对象(资源)提供访问入口。

资源是Web架构的关键点,需要3个操作:识别(identify)表示(represent)交互(interact with)

通过这三个操作,又引出三个概念:

  • uri(统一资源标识符包括url和urn)识别资源;
  • representation (例如html,图片,视频等等)表示资源;
  • 通过协议(包括http,ftp等等)与资源进行交互。

所以REST就是选择通过使用http协议和uri,利用client/server model对资源进行CRUD(Create/Read/Update/Delete)增删改查操作。

2.请求类型

REST不是”rest”这个单词,而是Resource Representational State Transfer的缩写:通俗来讲就是:资源在网络中以某种表现形式进行状态转移。分开来讲:

  • Resource:资源,即数据(网络的核心);
  • Representational:某种表现形式,比如用JSON,XML,JPEG等;
  • State Transfer:状态变化。通过HTTP动词实现。

REST描述的是在网络中client和server的一种交互形式;REST本身不实用,实用的是如何设计 RESTful API(REST风格的网络接口)。Server提供的RESTful API中,URL中只使用名词来指定资源,原则上不使用动词。“资源”是REST架构或者说整个网络处理的核心。用HTTP协议里的动词来实现资源的添加,修改。

Server和Client之间传递某资源的一个表现形式,比如用JSON,XML传输文本,或者用JPG,WebP传输图片等。用 HTTP Status Code传递Server的状态信息。比如最常用的 200 表示成功,500 表示Server内部错误等。

Web端不再用之前典型的PHP或JSP架构,而是改为前段渲染和附带处理简单的商务逻辑。Web端和Server只使用上述定义的API来传递数据和改变数据状态。格式一般是JSON。

对于资源的具体操作类型,由HTTP动词表示。常用的HTTP动词有下面五个(括号里是对应的SQL命令):

  • GET(SELECT):从服务器获取资源(一项或多项)
  • POST(CREATE):在服务器新建一个资源
  • PUT(UPDATE):在服务器更新资源(客户端提供改变后的完整资源)
  • PATCH(UPDATE):在服务器更新资源(客户端提供改变的属性)
  • DELETE(DELETE):从服务器删除资源。

以上内容摘自:什么是REST?作者:IT修真院。

3.SAP 如何提供 Http Service

如果要将 SAP 应用程序服务器 (application server)作为 http 服务提供者,需要定义一个类,这个类必须实现IF_HTTP_EXTENSION 接口。IF_HTTP_EXTENSION 接口只有一个方法 HANDLE_REQUEST。自定义的这个类必须实现 HANDLE_REQUEST 方法。HANDLE_REQUEST 方法的 SERVER 参数是一个 http server 对象 (类型为 ICF 框架的 IF_HTTP_SERVER 接口)。http server 对象具有的属性和方法对请求和响应进行处理。

然后使用 SICF 事务码创建服务,并且将处理器(handler)设定为自定义类。
客户端就可以访问这个服务。

以上内容摘自:【ABAP】REST/HTTP技术(一)作者:BearGeorge

二、接口的创建

1.TCODE SE24/SE80 新建接口类

使用TCODE SE24 / SE80 新建Rest的接口类。

1.新建接口类

选择类保存的Package。

2.类所保存的Package

2.添加接口 IF_HTTP_EXTENSION

在新建的Class中选择Interfaces页签,添加接口标准接口IF_HTTP_EXTENSION。输入接口名称之后回车绑定接口。

3.类中添加接口

3.实现接口方法

点击Methods页签可以看到上一步绑定接口时,接口需要实现的Method。

4.类中接口的Method

双击进入Method,在其中实现Rest接口根据不同请求方式所对应的逻辑。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
METHOD IF_HTTP_EXTENSION~HANDLE_REQUEST.
*--------------------------Variables-----------------------------------*
CONSTANTS:
LC_I TYPE C LENGTH 1 VALUE 'I',
LC_EQ TYPE C LENGTH 2 VALUE 'EQ',
LC_GET TYPE STRING VALUE 'GET',
LC_PUT TYPE STRING VALUE 'PUT',
LC_POST TYPE STRING VALUE 'POST',
LC_PATCH TYPE STRING VALUE 'PATCH',
LC_DELETE TYPE STRING VALUE 'DELETE',
LC_METHOD TYPE STRING VALUE '~request_method',
LC_RETUTYPE TYPE STRING VALUE 'application/json'.
"应用数据结构与内表
DATA:
BEGIN OF LS_DATA,
CARRID TYPE SFLIGHT-CARRID,
CONNID TYPE SFLIGHT-CONNID,
FLDATE TYPE SFLIGHT-FLDATE,
PRICE TYPE SFLIGHT-PRICE,
CURRENCY TYPE SFLIGHT-CURRENCY,
END OF LS_DATA,
LT_DATA LIKE TABLE OF LS_DATA,
LR_CARRID TYPE RANGE OF SFLIGHT-CARRID,
LR_CONNID TYPE RANGE OF SFLIGHT-CONNID,
LR_FLDATE TYPE RANGE OF SFLIGHT-FLDATE,
LS_CARRID LIKE LINE OF LR_CARRID,
LS_CONNID LIKE LINE OF LR_CONNID,
LS_FLDATE LIKE LINE OF LR_FLDATE.

"JSON抬头结构
DATA:
LT_FIELDS TYPE TIHTTPNVP.

"接口属性
DATA:
LV_MESGTEXT TYPE STRING,
LV_RETUCODE TYPE STRING,
LV_METHOD TYPE STRING, "获取GET/POST等请求方式
LV_RETU_JSON TYPE STRING, "返回参数的JSON
LV_GET_JSONS TYPE STRING, "获取单条的JSON
LV_GET_JSONT TYPE STRING. "获取多条的JSON
*----------------------------Logic-------------------------------------*
"获取JSON抬头数据
SERVER->REQUEST->GET_HEADER_FIELDS(
CHANGING
FIELDS = LT_FIELDS
).

"获取请求方式
LV_METHOD = SERVER->REQUEST->GET_HEADER_FIELD( NAME = LC_METHOD ).

"设置返回数据格式
CALL METHOD SERVER->RESPONSE->IF_HTTP_ENTITY~SET_CONTENT_TYPE
EXPORTING
CONTENT_TYPE = LC_RETUTYPE.

"获取JSON行数据
LV_GET_JSONS = SERVER->REQUEST->IF_HTTP_ENTITY~GET_CDATA( ).

"可选,主要是为了JSON了可读性
REPLACE ALL OCCURRENCES OF REGEX '\s(?=([^"]*"[^"]*")*[^"]*$)'
IN LV_GET_JSONS WITH ''. " 正则压缩json字符串空格

"将JSON转换为内表
IF LV_GET_JSONS IS NOT INITIAL.
/UI2/CL_JSON=>DESERIALIZE(
EXPORTING
JSON = LV_GET_JSONS
CHANGING
DATA = LS_DATA
).
ELSE.
"获取多条数据的JSON
LOOP AT LT_FIELDS INTO DATA(LS_FIELDS).
TRANSLATE LS_FIELDS-NAME TO UPPER CASE.
IF LS_FIELDS-NAME EQ 'LT_DATA'.
LV_GET_JSONT = LS_FIELDS-VALUE.
ENDIF.
CLEAR: LS_FIELDS.
ENDLOOP.

/UI2/CL_JSON=>DESERIALIZE(
EXPORTING
JSON = LV_GET_JSONT
CHANGING
DATA = LT_DATA
).
ENDIF.

"判断请求方式
CASE LV_METHOD.
WHEN LC_GET OR LC_POST.
"获取筛选条件
LS_CARRID-SIGN = LC_I.
LS_CARRID-OPTION = LC_EQ.
MOVE-CORRESPONDING LS_CARRID TO LS_CONNID.
MOVE-CORRESPONDING LS_CARRID TO LS_FLDATE.

IF LS_DATA IS NOT INITIAL.
APPEND LS_DATA TO LT_DATA.
ENDIF.

IF LT_DATA IS NOT INITIAL.
LOOP AT LT_DATA INTO LS_DATA.
IF LS_DATA-CARRID IS NOT INITIAL.
LS_CARRID-LOW = LS_DATA-CARRID.
APPEND LS_CARRID TO LR_CARRID.
ENDIF.

IF LS_DATA-CONNID IS NOT INITIAL.
LS_CONNID-LOW = LS_DATA-CONNID.
APPEND LS_CONNID TO LR_CONNID.
ENDIF.

IF LS_DATA-FLDATE IS NOT INITIAL.
LS_FLDATE-LOW = LS_DATA-FLDATE.
APPEND LS_FLDATE TO LR_FLDATE.
ENDIF.
CLEAR: LS_DATA.
ENDLOOP.
ENDIF.

SELECT CARRID CONNID FLDATE PRICE CURRENCY
FROM YSFLIGHT_CYH
INTO CORRESPONDING FIELDS OF TABLE LT_DATA
WHERE CARRID IN LR_CARRID
AND CONNID IN LR_CONNID
AND FLDATE IN LR_FLDATE.
IF SY-SUBRC NE 0.
LV_RETUCODE = 'E'.
LV_MESGTEXT = '数据未找到'.
ELSE.
LV_RETUCODE = 'S'.
LV_MESGTEXT = '数据查询成功'.
ENDIF.
WHEN LC_PUT.
WHEN LC_PATCH.
WHEN LC_DELETE.
WHEN OTHERS.
ENDCASE.

"返回数据到调用端
IF LV_RETUCODE EQ 'S'.
"将内表转换为JSON
CALL METHOD /UI2/CL_JSON=>SERIALIZE
EXPORTING
DATA = LT_DATA
RECEIVING
R_JSON = LV_RETU_JSON.
"将行数据JSON返回给调用端
SERVER->RESPONSE->SET_CDATA(
EXPORTING
DATA = LV_RETU_JSON
).
"设置状态码
SERVER->RESPONSE->SET_STATUS( CODE = 200 REASON = 'OK' ).
ELSE.
"设置返回的Message信息
SERVER->RESPONSE->SET_CDATA(
EXPORTING
DATA = LV_MESGTEXT
).
ENDIF.
ENDMETHOD.

三、创建Rest服务

1.使用TCODE SICF进入服务选择画面

5.创建服务子节点选择画面

2.创建服务子节点

6.创建服务子节点

3.填入服务元素名称

此处是服务的名称,并不一定要与类名一致。

7.选择服务子节点名称

4.设置服务属性参数

设置完服务节点的参数属性后,点击最上面的保存按钮。将服务保存到对应的Package‘中。

8.设置服务节点属性

5.激活服务子节点

在刚刚新建子节点的SAP目录下找到自己新建的服务子节点,然后右键激活服务。

9.激活服务子节点 10.激活子节点确认框

如此,一个REST 接口就创建完成了。

四、接口测试

1.获取Rest测试链接

11.服务节点测试获取测试地址

直接进行测试时是默认使用GET的请求方式。下图是我使用的别人的图片,因为我的SAP系统并不是这样的,所以此处作为参考借用一下。

12.外部替代图片-获取调用用URL

上面为其中一种测试的内容,下面这种是直接从网页打开的测试内容。

22.接口测试网页图片

2.创建SOAP UI的测试项目

测试软件的下载可以参考之前的接口文档:SAP Web Service的发布。或点击右边的地址下载SOAP UI。

14.SOAP UI新建REST 接口测试

之后输入刚刚获取到的Rest URL。

15.输入REST 接口的URL

会在左边的工具栏中生成本次测试的Rest接口项目。在右侧显示测试接口的内容等信息。

17.Rest接口测试功能界面

3.添加权限对象

直接测试可能会报401没有权限的Error,如下图所示。

20.权限异常界面

只需要按照下图所示的步骤,将自己的SAP账号或SAP顾问提供给你的账号填入下面的输入框中即可。

18.Rest测试 添加权限账号 19.添加完成权限对象

4.全局测试Rest接口

在红框处选择请求类型,然后查看详细的请求过程。

13.使用SOAPUI测试接口

另外在SOAP UI调用接口的时候,可以在类中添加外部端点。查看调用过程中参数的详细掉用过程。

16.外部断点测试

5.添加请求参数

上面测试的是查询全部的内容,接下来测试添加筛选参数的测试。因为SOAP UI想要向BODY中添加请求参数必须使用POST或PUT的请求类型,所以在上面代码的编写过程中,我将GET和POST两种请求方式的逻辑合并了。下面是参数请求过程的截图。

21.筛选参数请求结果

五、参考资料

SAP发布Rest接口实例(详细步骤)

【ABAP】REST/HTTP技术(一)

SAP之Http Rest接口发布

什么是REST?

评论